package compilers.AST.statement;

import java.util.Iterator;
import java.util.LinkedList;

import compilers.AST.Node;
import compilers.AST.expression.Expression;
import compilers.AST.types.TypeSpecifier;
import compilers.compiler.PGenerator;
import compilers.exceptions.SemanticalException;
import compilers.symbolTable.SymbolTableScope;

public class LoopStatement extends Statement {
	
	private Expression fExpression;
	private LinkedList<Statement> fStatements;

	public LoopStatement() {
		fStatements = new LinkedList<Statement>();
		
	}
	
	public LoopStatement(int lineNr) {
		super(lineNr);
		fStatements = new LinkedList<Statement>();
		
	}
	
	public void print(int identLevel) {
		println(identLevel, "LoopStatement");
		fExpression.print(identLevel+1);
		if (!fStatements.isEmpty()) {
			Iterator<Statement> it = fStatements.iterator();
			while (it.hasNext()) {
				it.next().print(identLevel+1);
			}
		}
	}
	
	public void setExpression(Expression expression) {
		fExpression = expression;
	}
	
	public void addStatement(Statement statement) {
		fStatements.add(statement);
	}
	
	public void checkSemantics(SymbolTableScope currentScope) throws SemanticalException {
		fExpression.checkSemantics(currentScope);
		if (fExpression.getResultType(currentScope) != TypeSpecifier.BOOLEAN) {
			throw new SemanticalException("The result type of the expression in the loop statement should be 'boolean'.", getLine());
		}
		
		Iterator<Statement> it = fStatements.iterator();
		while (it.hasNext()) {
			it.next().checkSemantics(currentScope.getChildScope(this));
		}
	}
	
	public void generatePcode(PGenerator pGen, SymbolTableScope currentScope) {
		if (fExpression.isConstant(currentScope)) {
			//TODO: Generate warning!
		}
		
		String label = "WHILE_" + this.fNodeId;
		pGen.beginLabel(label);
		
		//Generate code for the expression and jump
		fExpression.generatePcode(pGen, currentScope);
		pGen.conditionalJump("end_" + label);
		
		//Generate code for statements in while loop
		SymbolTableScope newScope = currentScope.getChildScope(this);
		
		Iterator<Statement> it = fStatements.iterator();
		while (it.hasNext()) {
			it.next().generatePcode(pGen, newScope);
		}
		
		//Generate code for unconditional jump to start a new iteration
		pGen.unconditionalJump("begin_" + label);
		
		pGen.endLabel(label);
	}

}
